import { openConfirmError, openConfirmTips } from './getUtils';
import InputNumber from '@/components/inputNumber/inputNumber'

const VALIDATE_PRICE_ERROR_MESSAGE = '售价乘以0.78需大于成本价'
const STAND_RATE_NULL_ERROR_MESSAGE = '标准加价率为空'
const COST_PRICE_NULL_ERROR_MESSAGE = '成本价不能为空'
const SALE_PRICE_NULL_ERROR_MESSAGE = '售价不能为空'
const RATE_TIPS_MESSAGE = '实际加价率与标准加价率超出10%范围'

const ERROR_RATE = 0.78
const TIPS_RATE = 0.1

const SUBMIT_FLAG = 1

const RECORD_CUTOFF_DATE = '2023-06-29 20:00:00' // 新旧售价单据分界日期点

// 错误column
const ERROR_COLUM = {
  title: '禁止提交原因',
  key: 'unSubmitReason',
  fixed: 'left',
  sortable: true,
  errorTip: true,
  notShowTip: true,
}
// 异常column
const TIPS_COLUMN = {
  title: '异常提示',
  key: 'abnormalTips',
  fixed: 'left',
  sortable: true,
  errorTip: true,
  notShowTip: true,
}

// 售价操作类型
export const SALE_OPT_TYPES = {
  Add: Symbol('add-sale-price'),
  Edit: Symbol('edit-sale-price')
}

/**
 * 获取确定精度后的价格值
 * @param {*} value
 * @rules
    * 当＜5 时 保留2位小数。
    * 当≥5小于100时 保留1位小数。
    * 当≥100时 保留0位小数。
    * 全部为四舍五入规则。
 */
export const getPrecisionPrice = value => {
  let precision
  if (value < 5) precision = 2
  if (value >= 5 && value < 100) precision = 1
  if (value >= 100) precision = 0
  return Number(value.toFixed(precision))
}

/**
 * 获取售价输入框
 * @param {*} h
 * @param {*} row
 * @param {*} prop
 * @returns el-input-number
 */
export const renderSalePriceInput = (h, row, prop = 'salePrice') => {
  return (
    <InputNumber
      value={row[prop]}
      min={0}
      size="mini"
      controls={false}
      onChange={val => { row[prop] = val ? Number(val.toFixed(3)) : val }} // 默认输入时保留三位小数，精度逻辑只在初始计算售价时使用
    />
  )
}

/**
 * 获取填充非正常原因的售价集合 by 前端校验
 * @param {* 表格数据} tableList
 * @param {* 售价页面操作类型} type
 * @returns
 */
export const getFillReasonListByFrontValidate = (tableList, type) => {
  const results = tableList.map(item => ({
    ...item,
    errors: getErrors(item),
    tips: getTips(item, type)
  }))
  return results
}

// 获取填充非正常原因的售价集合
export const getFillReasonListByBackendValidate = (tableList, abnormalMaps) => {
  const results = tableList.map(item => ({
    ...item,
    errors: (abnormalMaps[item.id] ?? {}).errors ?? null,
    tips: (abnormalMaps[item.id] ?? {}).tips ?? null
  }))
  return results
}

// 获取禁止提交原因
export const getErrors = rowItem => {
  const errors = []
  if (!rowItem.standardAddRate) errors.push(STAND_RATE_NULL_ERROR_MESSAGE)
  if (!rowItem.costPrice) errors.push(COST_PRICE_NULL_ERROR_MESSAGE)
  if (!rowItem.salePrice) errors.push(SALE_PRICE_NULL_ERROR_MESSAGE)
  if (!validatePrice(rowItem)) errors.push(VALIDATE_PRICE_ERROR_MESSAGE)
  if (errors.length == 0) return null
  return errors
}

// 获取异常提示原因
export const getTips = (rowItem, type) => {
  const tips = []
  const validateMaps = {
    [SALE_OPT_TYPES.Add]: add_validateRateLimit,
    [SALE_OPT_TYPES.Edit]: edit_validateRateLimit
  }
  const validateFn = validateMaps[type] ?? (() => { throw new Error('There is an error in the front-end check method') })
  if (validateFn(rowItem) > TIPS_RATE) tips.push(RATE_TIPS_MESSAGE)
  if (tips.length == 0) return null
  return tips
}

// 校验是否含有禁止提交原因
export const validateErrors = submitResults => submitResults.some(item => item.errors)

// 校验是否含有异常提示原因
export const validateTips = submitResults => submitResults.some(item => item.tips)

export const isEmptyVal = value => value == undefined || value == null

// 获取初始详情数据 - 获取初始数据详情时，售价为空的进行默认规则计算，重新生成售价
export const getInitSaleDetails = tableList => tableList.map(item => ({
  ...item,
  salePrice: isEmptyVal(item.salePrice) ? getCalcSalePrice(item) : item.salePrice,
}))

/**
 * 售价校验
 * @rules 售价乘以0.78需大于成本价
 * @param { 售价 } salePrice
 * @param { 成本价 } costPrice
 * @returns { 售价是否符合规则 }
*/
const validatePrice = rowItem => {
  const { salePrice, costPrice } = rowItem ?? {}
  if (!salePrice) return true // 售价为空不再进行逻辑校验
  const numSalePrice = Number(salePrice) // 售价
  const numCostPrice = Number(costPrice) // 成本价
  const isSaleBigger =  numSalePrice * ERROR_RATE > numCostPrice
  return isSaleBigger
}

/**
 * 获取默认根据标准加价率计算所得售价 - 只在获取详情数据时，售价为null的进行默认计算
 * @param {* 当前表格行数据} rowItem
 * @key {* 成本价} costPrice
 * @key {* 标准加价率} standardAddRate
 * @formula 成本价 *（1+标准加价率）保留售价小数位取舍逻辑
 * @returns
 */
export const getCalcSalePrice = rowItem => {
  const numCosePrice = Number(rowItem.costPrice) // 成本价
  const numAddRate = 1 + Number(rowItem.standardAddRate) // 1 + 标准加价率
  // 售价 =（1 + 标准加价率）* 成本价
  const salePrice = numAddRate * numCosePrice
  return getPrecisionPrice(salePrice)
}

// 获取售价实际加价率
export const getActualAddRate = (rowItem, saleProp = 'salePrice') => {
  if (!rowItem.salePrice) return '' // 没有售价时默认为空
  const numSalePrice = Number(rowItem[saleProp] ?? 0)
  const numCostPrice = Number(rowItem.costPrice ?? 0)
  const rate = (numSalePrice - numCostPrice) / numCostPrice // 实际加价率 = (售价 - 成本价)/成本价 === 售价/成本价 - 1
  const acutalRate = rate.toFixed(2)
  return acutalRate
}

// 校验 - 售价实时加价率 - 标准加价率 > 0.1 - 准入新增（准入前）
const add_validateRateLimit = rowItem => {
  if (!getActualAddRate(rowItem)) return false // 实时加价率为空不再进行逻辑校验
  const actualAddRate = Number(getActualAddRate(rowItem)) // 实际加价率
  const standardAddRate = Number(rowItem.standardAddRate ?? 0) // 标准加价率
  //（实际加价率 - 标准加价率）的绝对值 > 0.1
  const valid = Math.abs(actualAddRate - standardAddRate) > TIPS_RATE
  return valid
}

// 校验 - 售价实时加价率现值 - 售价实时加价率原值 > 0.1 - 修改售价（准入后）
const edit_validateRateLimit = rowItem => {
  if (!getActualAddRate(rowItem)) return false // 实时加价率为空不再进行逻辑校验
  const actualAddRate = Number(getActualAddRate(rowItem)) // 售价现值实际加价率（新实际加价率）
  const oldActualAddRate = Number(getActualAddRate(rowItem, 'oldSalePrice')) // 售价原值实际加价率（老实际加价率）
  //（老实际加价率 - 新实际加价率）的绝对值 > 0.1
  const valid = Math.abs(oldActualAddRate - actualAddRate) > TIPS_RATE
  return valid
}

// 获取异常提示错误信息拼接后的表格数据
const getTableDataByJoinStr = tableList => tableList.map(item => ({
  ...item,
  [ERROR_COLUM.key]: item.errors ? item.errors.join('，') : '',
  [TIPS_COLUMN.key]: item.tips ? item.tips.join('，') : ''
}))

// 获取错误原因参数
const getErrorArgs = updateSubmitResults => ({
  hasErrorData: validateErrors(updateSubmitResults),
  list: updateSubmitResults,
  columns: [ERROR_COLUM, TIPS_COLUMN]
})

// 获取异常提示参数
const getTipsArgs = updateSubmitResults => ({
  hasTipMsg: validateTips(updateSubmitResults),
  list: updateSubmitResults,
  columns: [TIPS_COLUMN]
})

/**
 * 更新表格数据 - 前端校验
 * @param {* 准入前后类型（即准入和修改） } type
 * @returns 针对准入前后不同的校验方法
 */
export const processFrontendValidateResults = type => {
  return (tableData, callback) => {
    const submitResults = getFillReasonListByFrontValidate(tableData, type)
    processSubmitProgress(submitResults, callback)
  }
}

// 更新表格数据 - 售价提交校验 - 准入新增（准入前）
export const processFrontendValidateResultsAdd = processFrontendValidateResults(SALE_OPT_TYPES.Add)

// 更新表格数据 - 售价提交校验 - 修改售价（准入后）
export const processFrontendValidateResultsEdit = processFrontendValidateResults(SALE_OPT_TYPES.Edit)

// 更新表格数据 - 后端校验
export const processBackendValidateResults = (tableData, ErrorMaps, callback) => {
  const submitResults = getFillReasonListByBackendValidate(tableData, ErrorMaps)
  processSubmitProgress(submitResults, callback)
}

/**
 * 处理提交流程
 * @param {* 提交结果集} submitResults
 * @param {* 提交执行回调} callback
 */
export const processSubmitProgress = (submitResults, callback) => {
  const updateSubmitResults = getTableDataByJoinStr(submitResults) // 扁平错误errors和提示tips后的表格数据
  // 有错误原因时执行错误弹窗逻辑
  const errorArgs = getErrorArgs(updateSubmitResults)
  if (errorArgs?.hasErrorData) return openConfirmError(() => { callback(errorArgs) })
  // 有异常提示时执行异常弹窗逻辑
  const tipsArgs = getTipsArgs(updateSubmitResults)
  if (tipsArgs?.hasTipMsg) {
    const onSuccess = () => { callback({ ...tipsArgs, submitFlag: SUBMIT_FLAG }) } // 仍要提交执行方法
    const onCancel = () => { callback(tipsArgs) } // 取消执行方法
    return openConfirmTips(onSuccess, onCancel)
  }
  // 没有错误原因和异常提示，正常进行提交
  callback()
}

// 获取无错误异常提示字段的提交价格列表数据
export const getSalesWithoutMessage = priceList => priceList.map(item => _.omit(item,
  ['errors', [ERROR_COLUM.key], 'tips', [TIPS_COLUMN.key]
]))

// 根据单据号中的日期字符获取转换后的时间戳
export const getTimestampByRecordDate = recordNo => {
  const regex = /^RECORD(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/
  const regex1 = /^RECORD_BATCH_(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/
  const timeMatches = recordNo.match(regex)
  const timeMatches1 = recordNo.match(regex1)
  if (!timeMatches && !timeMatches1) return
  const [, year, month, day, hour, minute, second] = timeMatches ?? timeMatches1 ?? []
  const datetimeStr = `${year}-${month}-${day} ${hour}:${minute}:${second}`
  const timestamp = new Date(datetimeStr).getTime()
  return timestamp
}

// 比对单据日期是否早于某个时间点
export const isBeforeTimestamp = (targetTimestamp, compareTimeStr) => {
  if (!compareTimeStr) compareTimeStr = RECORD_CUTOFF_DATE
  const compareTimestamp = new Date(compareTimeStr).getTime()
  return targetTimestamp < compareTimestamp
}

// 根据单据号对比时间是否早于某个时间点
export const isBeforeRecordDate = (recordNo, compareTimeStr) => {
  if (!compareTimeStr) compareTimeStr = RECORD_CUTOFF_DATE
  const targetTimestamp = getTimestampByRecordDate(recordNo)
  const compareTimestamp = new Date(compareTimeStr).getTime()
  return targetTimestamp < compareTimestamp
}

// 获取售价浮动率 (（现值 - 原值）/ 原值) * 100 百分号保留2位小数
export const getSaleFloatRate = (newSalePrice, oldSalePrice) => {
  const newVal = Number(newSalePrice)
  const oldVal = Number(oldSalePrice)
  const rateNum = ((newVal - oldVal) / oldVal) * 100
  const floatNum = rateNum.toFixed(2)
  return floatNum
}
